#include <iostream>
#include <cassert>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <cstring>
using namespace std;
#define MAX 1024

// 管道的4种情况
//  1、正常情况下，如果管道没有数据了，那么读端就必须等待，直到有数据为止(写端写数据)
//  2、正常情况下，如果管道被写满了，那么写端就必须等待，直到有空间为止(读端读数据)
//  3、如果让写端在写入的过程中直接关闭，让读端一直读,读端恢复到read返回值为0，表示读到文件结尾
//  4、而如果是读端关闭，让写端一直写,写已经没有意义了，操作系统会直接杀掉写端进程

// 管道的5种特性
//  1、匿名管道可以允许具有血缘关系的进程之间的信息通信，场用于父子进程，但也就仅限于此
//  2、匿名管道默认要给读写端提供同步机制
//  3、匿名管道是面向“字节流”的
//  4、管道的生命周期是随进程的
//  5、管道是单向通通信的，它是半双工通信的一种特殊情况



int main() {
    // 实现管道通信的第一步：建立管道
    int pipefd[2] = { 0 };
    int n = pipe(pipefd);
    assert(n == 0);
    //(void*)n; // 只是为了防止编译器告警

    // 第二步：创建子进程
    pid_t id = fork();

    // 子进程写入，父进程读取
    // 第三步：父子进程关闭不需要的文件描述符，形成单向的通信管道
    if (id == 0) {
        // child
        close(pipefd[0]); // 子进程要写，所以子进程需要关闭读的文件描述符
        int count = 10000;
        while (true) {
            char msg[MAX];
            snprintf(msg, sizeof(msg), "are you OK? father I am your child my pid id %d, my count is %d", getpid(), count);
            write(pipefd[1], msg, strlen(msg));
            //sleep(100);
            cout << "write…… count: " << count << endl; 
            // if (count == 9997) {
            //     cout << "child process quit" << endl;
            //     break;
            // }
            sleep(1);
        }

        close(pipefd[1]);
        exit(0);

    } else if (id < 0) {
        perror("fork()");
        return -1;
    }


    // father
    close(pipefd[1]); // 父进程要读，所以关闭写的文件描述符
    int cnt = 8;
    while (cnt--) {
        char buffer[MAX];
        //sleep(200);

        ssize_t res = read(pipefd[0], buffer, sizeof(buffer) - 1);
        // if (!res) {
        //     break;
        // } else if (res > 0) {
        //     buffer[res] = '\0';
        // }
        cout << "father return val: " << res << endl;
        if (res == 0) {
            cout << "child quit, me too" << endl;
            break;
        }

        cout << "child process say : “" << buffer << "” to me" << endl;
        sleep(1);
    }
    cout << "father quit" << endl;
    close(pipefd[0]);

    // 等待，回收子进程资源
    int status = 0;
    pid_t rid = waitpid(id, &status, 0);
    if (rid == id) {
        cout << "wait sucess! quit signal:" << (status&0x7F) << endl;
    }
    return 0;
}